package com.bestcem.xm.txtanls.controller;


import cn.hutool.core.lang.ObjectId;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.txtanls.controller.param.chart.BaseChartQuery;
import com.bestcem.xm.txtanls.controller.param.topic.UpdateTopicQuery;
import com.bestcem.xm.txtanls.grpc.service.param.chart.BaseChartParam;
import com.bestcem.xm.txtanls.grpc.service.param.topic.*;
import com.bestcem.xm.txtanls.service.AnalysisProjectService;
import com.bestcem.xm.txtanls.service.TopicService;
import com.bestcem.xm.txtanls.service.dto.analysis.AnalysisProjectDTO;
import com.bestcem.xm.txtanls.service.dto.topic.TopicDataDTO;
import com.bestcem.xm.txtanls.service.dto.topic.TopicGroupDTO;
import com.bestcem.xm.txtanls.util.ChartUtil;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.*;

import static com.bestcem.xm.common.core.constant.Constants.*;

/**
 * 话题controller类
 *
 * @author liheng
 * @version v2.0
 * @date 2021/8/6 10:21
 */
@Slf4j
@RestController
@RequestMapping(value = "/txtanls/", produces = MediaType.APPLICATION_JSON_VALUE)
public class TopicController {

    @Resource
    private TopicService topicService;

    @Resource
    private AnalysisProjectService analysisProjectService;

    /**
     * 新增话题/组
     *
     * @param createTopicParam 创建话题参数
     * @return 响应信息
     */
    @PostMapping(value = "topic/")
    public XmResultJson<String> createTopic(@RequestBody CreateTopicParam createTopicParam) {
        Set<ConstraintViolation<Object>> validation = GRpcUtil.validateParam(createTopicParam);
        if (!CollectionUtils.isEmpty(validation)) {
            ConstraintViolation<Object> violation = validation.iterator().next();
            return XmResultJson.fail(4, violation.getMessage());
        }
        ServiceResult<String> result = topicService.saveTopic(createTopicParam);
        if (result.isSuccess()) {
            return XmResultJson.success(result.getData());
        } else {
            return XmResultJson.fail(5, result.getMsg());
        }
    }

    /**
     * 修改话题/组
     *
     * @param id    话题id
     * @param query 修改update
     * @return
     */
    @PutMapping(value = "topic/{id}")
    public XmResultJson<String> updateTopic(@PathVariable String id, @RequestBody UpdateTopicQuery query) {

        if (StringUtils.isNotBlank(query.getTopicGName()) || StringUtils.isNotBlank(query.getTopicGId())) {
            // 移动话题组
            MoveTopicParam param = new MoveTopicParam(id, query.getProjectId(), query.getTopicGName(), query.getTopicGId());
            ServiceResult<String> result = topicService.moveTopic(param);
            if (result.isSuccess()) {
                return XmResultJson.success(result.getData());
            } else {
                return XmResultJson.fail(5, result.getMsg());
            }
        }
        if (StringUtils.isNotBlank(query.getProjectId()) || Objects.nonNull(query.getType())) {
            return XmResultJson.fail(5, "话题类型和项目id不能更改");
        }
        UpdateTopicParam updateTopicParam = new UpdateTopicParam();
        updateTopicParam.setId(id);
        if (StringUtils.isNotBlank(query.getName())) {
            // 修改话题名
            updateTopicParam.setUpdateKeywordFlag(false);
        } else if (Objects.nonNull(query.getKeyDict())) {
            // 校验关键词长度
            List<String> keyDict = query.getKeyDict();
            for (String s : keyDict) {
                if (s.length() > 50) {
                    return XmResultJson.fail(5, "关键字长度不能超过50");
                }
            }
            // 设置为修改关键词
            updateTopicParam.setUpdateKeywordFlag(true);
        }
        updateTopicParam.setName(query.getName());
        updateTopicParam.setKeywords(query.getKeyDict());
        updateTopicParam.setProjectId(query.getProjectId());
        ServiceResult<String> result = topicService.updateTopic(updateTopicParam);
        if (result.isSuccess()) {
            return XmResultJson.success(result.getData());
        } else {
            return XmResultJson.fail(5, result.getMsg());
        }
    }

    /**
     * 删除话题/组
     *
     * @param id 话题id
     * @return 返回被删除的id
     */
    @DeleteMapping(value = "topic/{id}")
    public XmResultJson<String> deleteTopic(@PathVariable(value = "id") String id) {
        ServiceResult<String> result = topicService.deleteTopic(id);
        if (result.isSuccess()) {
            return XmResultJson.success(result.getData());
        } else {
            return XmResultJson.fail(5, result.getMsg());
        }
    }

    /**
     * 查询话题列表
     *
     * @param projectId  文本分析项目id
     * @param dataUse    是否使用过滤条件。0-使用过滤条件，1-不使用过滤条件
     * @param fieldId    分析字段id
     * @param filterType 时间区间过滤类型
     * @param current    当前日期字符串
     * @param startTime  起始时间
     * @param endTime    截止时间
     * @return 返回话题组list
     */
    @GetMapping(value = "topicgroups/")
    public XmResultJson<List<TopicGroupDTO>> listTopicGroup(@RequestParam(value = "projectid") String projectId, @RequestParam(value = "data_use", required = false) Integer dataUse,
                                                            @RequestParam(value = "field_id", required = false) String fieldId, @RequestParam(value = "dtfiltertype", required = false) String filterType,
                                                            @RequestParam(value = "current", required = false) String current,
                                                            @RequestParam(value = "start_time", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startTime,
                                                            @RequestParam(value = "end_time", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endTime) {
        if (!ObjectId.isValid(projectId)) {
            return XmResultJson.fail(4, "缺少项目id");
        }
        ListTopicGroupParam param = new ListTopicGroupParam();
        dataUse = Optional.ofNullable(dataUse).orElse(ONE);
        if (dataUse == INT_ZERO) {
            BaseChartQuery baseChartQuery = new BaseChartQuery();
            baseChartQuery.setCurrent(current);
            baseChartQuery.setStartTime(startTime);
            baseChartQuery.setEndTime(endTime);
            baseChartQuery.setFilterType(filterType);
            BaseChartParam baseChartParam = baseChartQuery.getBaseChartParam();
            param.setTimeRangeDTO(baseChartParam.getTimeRangeDTO());
            if (Objects.isNull(baseChartParam.getTimeRangeDTO().getPeriodTime())) {
                return XmResultJson.fail(5, "参数错误");
            }
        }
        param.setFieldId(fieldId);
        param.setProjectId(projectId);
        ServiceResult<List<TopicGroupDTO>> result = topicService.listGroupByProjectId(param);
        if (result.isSuccess()) {
            return XmResultJson.success(result.getData());
        } else {
            return XmResultJson.fail(5, result.getMsg());
        }
    }

    /**
     * 导入话题
     *
     * @param projectId 文本分析项目id
     * @param file      上传文件
     * @return 上传结果
     */

    @PostMapping(value = "topic/upload/{id}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public XmResultJson<String> importTopics(@PathVariable(value = "id") String projectId, MultipartFile file) {
        String fileName = file.getOriginalFilename();
        if (StringUtils.isBlank(fileName)) {
            return XmResultJson.fail(5, "导入话题失败");
        }
        if (!(fileName.lastIndexOf(".xlsx") == fileName.indexOf(".xlsx") || fileName.lastIndexOf(".xls") == fileName.indexOf(".xls"))) {
            return XmResultJson.fail(ValidationErrorCodeEnum.FILE_TYPE_NOT_RIGHT, ResourceErrorCodeEnum.INVALID_FORMAT.getMsg());
        }
        if (file.getSize() / 1048576L > 10L) {
            // 显示文件上传大小10m
            return XmResultJson.fail(ResourceErrorCodeEnum.FILE_TOO_LARGE, "文件过大");
        }

        List<TopicDataDTO> topicDataList = new ArrayList<>(DEFAULT_ARRAY_SIZE);
        ImportTopicParam importTopicParam = new ImportTopicParam(projectId, topicDataList);

        try (InputStream inputStream = file.getInputStream()) {

            EasyExcel.read(inputStream, TopicDataDTO.class, new TopicDataListener(topicDataList)).doReadAll();
        } catch (IOException e) {
            return XmResultJson.fail(5, "导入话题失败");
        }
        ServiceResult<Object> result = topicService.importTopicData(importTopicParam);
        if (!result.isSuccess()) {
            return XmResultJson.fail(5, result.getMsg());
        }
        return XmResultJson.success(projectId);
    }

    /**
     * 导出话题信息
     *
     * @param id       文本分析项目id
     * @param response 响应
     * @return void
     * @version v1.0
     * @author gy.liu
     * @date 2021/8/6
     */
    @SneakyThrows
    @ApiOperation(value = "导出话题信息")
    @GetMapping(value = "/topic/export/{id}")
    public void exportTopic(@PathVariable(value = "id") String id, HttpServletResponse response) {

        if (!ObjectId.isValid(id)) {
            ChartUtil.excelErrorResponse(response, 4, "文本分析项目id错误", "txtanls");
        }
        ServiceResult<AnalysisProjectDTO> projectResult = analysisProjectService.getById(id);
        if (!projectResult.isSuccess()) {
            try {
                response.getWriter().println(JSON.toJSONString(XmResultJson.fail(4, projectResult.getMsg())));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        AnalysisProjectDTO project = projectResult.getData();
        ServiceResult<List<TopicDataDTO>> result = topicService.exportTopicData(id);
        ArrayList<TopicDataDTO> topicDataDTOS = new ArrayList<>(DEFAULT_ARRAY_SIZE);
        topicDataDTOS.add(new TopicDataDTO("话题组", "话题", "关键词"));
        List<TopicDataDTO> data = result.getData();
        topicDataDTOS.addAll(data);
        // 导出话题关键词信息
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode(project.getName() + "_话题&关键词", UTF_8);
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream()).autoCloseStream(Boolean.FALSE).sheet("话题&关键词")
                    .doWrite(topicDataDTOS);
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                log.error("[txtanls]: 导出话题出现异常:", e);
            }
            ChartUtil.excelErrorResponse(response, 4, "原话导出出现异常", "txtanls");
        }
    }


    /**
     * easyExcel写excel处理类
     */
    @Slf4j
    private static class TopicDataListener extends AnalysisEventListener<TopicDataDTO> {

        List<TopicDataDTO> list;

        public TopicDataListener(List<TopicDataDTO> inputList) {
            this.list = inputList;
        }

        @Override
        public void invoke(TopicDataDTO map, AnalysisContext analysisContext) {
            if (log.isInfoEnabled()) {
                log.info("解析一条数据成功：{}", map);
            }
            list.add(map);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            if (log.isInfoEnabled()) {
                log.info("[Txtanls] 上传话题信息读取完成，数据条数：{}", list.size());
            }

        }
    }
}
